package gee

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type H map[string]interface{}

type Context struct {
	//request or response info
	Req        *http.Request
	Res        http.ResponseWriter
	Path       string
	Method     string
	Params     map[string]string
	StatusCode int
	// middlewares
	handlers []HandlerFunc
	index    int
	engine   *Engine
}

func newContext(req *http.Request, res http.ResponseWriter) *Context {
	return &Context{
		Req:    req,
		Res:    res,
		Path:   req.URL.Path,
		Method: req.Method,
		index:  -1,
	}
}

func (ctx *Context) Param(key string) string {
	value, _ := ctx.Params[key]
	return value
}

func (ctx *Context) SetStatusCode(code int) {
	ctx.StatusCode = code
	ctx.Res.WriteHeader(ctx.StatusCode)
}

func (ctx *Context) SetHeader(key string, value string) {
	ctx.Res.Header().Set(key, value)
}

func (ctx *Context) Get(key string) string {
	return ctx.Req.URL.Query().Get(key)
}

func (ctx *Context) FormValue(key string) string {
	return ctx.Req.FormValue(key)
}

func (ctx *Context) Post(key string) string {
	return ctx.Req.PostFormValue(key)
}

func (ctx *Context) String(code int, format string, any ...interface{}) {
	ctx.SetHeader("content-type", "text/plain")
	ctx.SetStatusCode(code)
	ctx.Res.Write([]byte(fmt.Sprintf(format, any...)))
}

func (ctx *Context) Data(code int, value []byte) {
	ctx.SetStatusCode(code)
	ctx.Res.Write(value)
}

func (ctx *Context) Html(code int, name string, data H) {
	ctx.SetHeader("content-type", "text/html")
	ctx.SetStatusCode(code)
	if err := ctx.engine.templates.ExecuteTemplate(ctx.Res, name, data); err != nil {
		http.Error(ctx.Res, err.Error(), http.StatusInternalServerError)
	}
}

func (ctx *Context) Json(code int, object interface{}) {
	ctx.SetHeader("content-type", "application/json")
	content, err := json.Marshal(object)
	if err != nil {
		http.Error(ctx.Res, err.Error(), http.StatusInternalServerError)
		return
	}

	ctx.SetStatusCode(code)
	ctx.Res.Write(content)
}

func (ctx *Context) Next() {
	ctx.index++
	count := len(ctx.handlers)
	if ctx.index < count {
		ctx.handlers[ctx.index](ctx)
	}
}
